package calcs;

import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static util.UserInputChecker.checkInput;
import static util.UserInputChecker.setCalculated;
import static util.UserInputChecker.setInitial;
import static util.Util.roundToDecimals;
import gui.ErrorMessage;
import gui.MyFrame;
import gui.data.D3.PolyhedronOutputGui;

public class PolyhedronCalculator extends Thread {
	int guide;
	double radius, side, volume, area, sArea, bArea, height;
	boolean boolSide, boolVolume, boolArea, boolsArea, boolbArea, boolHeight;
	double pi = Math.PI;
	boolean found = false, before = false, calculated = false;
	MyFrame myFrame;

	public PolyhedronCalculator(int guide, double radius, double side,
			double volume, double area, double sArea, double bArea,
			double height, final MyFrame myFrame) {
		this.myFrame = myFrame;
		this.guide = guide;
		this.radius = radius;
		this.side = side;
		this.volume = volume;
		this.sArea = sArea;
		this.bArea = bArea;
		this.area = area;
		this.height = height;
		setInitial(radius, side, volume, area, sArea, bArea, height);
		start();
	}

	public PolyhedronCalculator(int guide, double radius, double side,
			double volume, double area, double sArea, double bArea,
			double height) {
		this.guide = guide;
		this.radius = radius;
		this.side = side;
		this.volume = volume;
		this.sArea = sArea;
		this.bArea = bArea;
		this.area = area;
		this.height = height;
	}

	public void run() {
		switch (guide) {
		case 1:
			calculateCylinder();
			break;
		case 2:
			calculatePrism();
			break;
		}
		finish();
	}

	private void finish() {
		side = roundToDecimals(side, 2);
		bArea = roundToDecimals(bArea, 2);
		sArea = roundToDecimals(sArea, 2);
		radius = roundToDecimals(radius, 2);
		volume = roundToDecimals(volume, 2);
		area = roundToDecimals(area, 2);
		height = roundToDecimals(height, 2);
		if (myFrame != null) {
			setCalculated(radius, side, volume, area, sArea, bArea, height);
			if (checkInput()) {
				myFrame.setDataPanel(new PolyhedronOutputGui(guide, radius,
						side, volume, area, sArea, bArea, height),
						"POLYHEDRON_OUTPUT");
			} else {
				new ErrorMessage("Check input");
			}
		}
	}

	private void calculateCylinder() {
		do {
			found = false;
			before = false;
			calculated = false;

			before = radius != 0;
			calculateCylinderRadius();
			if (!before && found) {
				calculated = true;
			}

			before = bArea != 0;
			calculateCylinderBottomArea();
			if (!before && found) {
				calculated = true;
			}

			before = sArea != 0;
			calculateCylinderSideArea();
			if (!before && found) {
				calculated = true;
			}

			before = height != 0;
			calculateCylinderHeight();
			if (!before && found) {
				calculated = true;
			}

			before = area != 0;
			calculateCylinderArea();
			if (!before && found) {
				calculated = true;
			}

			before = volume != 0;
			calculateCylinderVolume();
			if (!before && found) {
				calculated = true;
			}
		} while (calculated);
	}

	private void calculateCylinderVolume() {
		if (height != 0 && bArea != 0) {
			volume = bArea * height;
			found = true;
		}
	}

	private void calculateCylinderArea() {
		if (bArea != 0 && sArea != 0) {
			area = (2 * bArea) + sArea;
			found = true;
		}
	}

	private void calculateCylinderHeight() {
		if (sArea != 0 && radius != 0) {
			height = sArea / (2 * pi * radius);
			found = true;
		} else if (volume != 0 && bArea != 0) {
			height = volume / bArea;
			found = true;
		}
	}

	private void calculateCylinderSideArea() {
		if (radius != 0 && height != 0) {
			sArea = 2 * pi * radius * height;
			found = true;
		} else if (area != 0 && bArea != 0) {
			sArea = area - (2 * bArea);
			found = true;
		}
	}

	private void calculateCylinderBottomArea() {
		if (radius != 0) {
			bArea = pi * pow(radius, 2);
			found = true;
		} else if (area != 0 && sArea != 0) {
			bArea = (area - sArea) / 2;
			found = true;
		} else if (volume != 0 && height != 0) {
			bArea = volume / height;
			found = true;
		}
	}

	private void calculateCylinderRadius() {
		if (bArea != 0) {
			radius = sqrt(bArea / pi);
			found = true;
		} else if (sArea != 0 && height != 0) {
			radius = sArea / (2 * pi * height);
			found = true;
		}
	}

	private void calculatePrism() {
		do {
			found = false;
			before = false;

			before = side != 0;
			calculatePrismSide();
			if (before) {
				found = false;
			}

			before = bArea != 0;
			calculatePrismBottomArea();
			if (before) {
				found = false;
			}

			before = sArea != 0;
			calculatePrismSideArea();
			if (before) {
				found = false;
			}

			before = height != 0;
			calculatePrismHeight();
			if (before) {
				found = false;
			}

			before = area != 0;
			calculatePrismArea();
			if (before) {
				found = false;
			}

			before = volume != 0;
			calculatePrismVolume();
			if (before) {
				found = false;
			}
		} while (found);
	}

	private void calculatePrismVolume() {
		if (height != 0 && bArea != 0) {
			volume = bArea * height;
			found = true;
		}
	}

	private void calculatePrismArea() {
		if (bArea != 0 && sArea != 0) {
			area = (2 * bArea) + sArea;
			found = true;
		}
	}

	private void calculatePrismHeight() {
		if (sArea != 0 && side != 0) {
			height = sArea / (4 * side);
			found = true;
		} else if (volume != 0 && bArea != 0) {
			height = volume / bArea;
			found = true;
		}
	}

	private void calculatePrismSideArea() {
		if (area != 0 && bArea != 0) {
			sArea = area - (2 * bArea);
			found = true;
		} else if (side != 0 && height != 0) {
			sArea = 4 * side * height;
			found = true;
		}
	}

	private void calculatePrismBottomArea() {
		if (side != 0) {
			bArea = pow(side, 2);
			found = true;
		} else if (area != 0 && sArea != 0) {
			bArea = (area - sArea) / 2;
			found = true;
		} else if (volume != 0 && height != 0) {
			bArea = volume / height;
			found = true;
		}
	}

	private void calculatePrismSide() {
		if (bArea != 0) {
			side = sqrt(bArea);
			found = true;
		} else if (sArea != 0 && height != 0) {
			side = sArea / (4 * height);
			found = true;
		}
	}
}
